#pragma once
#include <map>
#include <sstream>
#include <fstream>

#include "BaseException.h"

using namespace std;


// C...F...R => 03 + 06 + 18 = 27 = 0x1B
class ConfigFileReaderError : public BaseException
{
public:
  // Define errCodes
  static const short OPEN_CONFIG_FILE_ERROR = 0x1B00;
  static const short READ_CONFIG_FILE_ERROR = 0x1B01;
  static const short ATTR_NAME_NOT_FOUND    = 0x1B02;
  static const short ATTR_TYPE_ERROR        = 0x1B03;

  ConfigFileReaderError ()
  {
    __errMap.insert (std::make_pair (OPEN_CONFIG_FILE_ERROR, "Cannot open the config file"));
    __errMap.insert (std::make_pair (READ_CONFIG_FILE_ERROR, "Fail to read the config file, probably the file is damaged or in wrong format"));
    __errMap.insert (std::make_pair (ATTR_NAME_NOT_FOUND, "No attribute of the name is found"));
    __errMap.insert (std::make_pair (ATTR_TYPE_ERROR, "Cannot convert the type of this attribute value to the required type"));
  }
};


class ConfigFileReader
{
private:
  map< wstring, wstring > _attrs;

public:
  ConfigFileReader(void) {}
  ConfigFileReader (const wstring& configFileName)
  {
    read (configFileName);
  }

  void read (const wstring& configFileName)
  {
    wifstream fileReader (configFileName.c_str ());
    if (!fileReader)
      CTHROW_INFO (ConfigFileReaderError, ConfigFileReaderError::OPEN_CONFIG_FILE_ERROR, configFileName);
    while (!fileReader.eof ())
    {
      wstring anItem;
      getline (fileReader, anItem);
      if (fileReader.fail () || fileReader.bad ())
        CTHROW (ConfigFileReaderError, ConfigFileReaderError::READ_CONFIG_FILE_ERROR);
      int separator = anItem.find_first_of (L'=');
      if (separator == -1)
        CTHROW (ConfigFileReaderError, ConfigFileReaderError::READ_CONFIG_FILE_ERROR);
      wstring attrName = anItem.substr (0, separator);
      wstring attrValue = anItem.substr (separator + 1);
      _attrs.insert (make_pair (attrName, attrValue));
    }
  }

  wstring getWStrAttrVal (const wstring& attributeName)
  {
    map< wstring, wstring >::iterator iter = _attrs.find (attributeName);
    if (iter == _attrs.end ())
      CTHROW (ConfigFileReaderError, ConfigFileReaderError::ATTR_NAME_NOT_FOUND);
    return iter->second;
  }

  template< class T >
  T getAttrVal (const wstring& attributeName)
  {
    wstring strAttrVal = getWStrAttrVal (attributeName);
    T attrVal;
    wistringstream converter (strAttrVal);
    converter >> attrVal;
    if (converter.bad () || converter.fail ())
      CTHROW (ConfigFileReaderError, ConfigFileReaderError::ATTR_TYPE_ERROR);
    return attrVal;
  }

};





